package feizhou.untils.tools;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;


/**
 * ftp上传，下载 工具类
 *
 * @author <a href="mailto:wanglu@smartdot.com.cn">wanglu</a>
 * @since 1.0, 2020年10月26日
 */
public class FtpUtil {

    private final static Log logger = LogFactory.getLog(FtpUtil.class);

    private static String ftpHost = "192.168.102.182";// FTP主机服务器
    private static String ftpUserName = "hd";// FTP登录用户名
    private static String ftpPassword = "hd";// FTP登录密码
    private static int ftpPort = 21;//  FTP端口 默认为21

    /**
     * 获取FTPClient对象
     */
    public static FTPClient getFTPClient() {
        FTPClient ftpClient = new FTPClient();
        try {

            // 设置连接超时时间
            ftpClient.setConnectTimeout(50 * 1000);
            // 设置数据超时时间
            ftpClient.setDataTimeout(50 * 1000);
            ftpClient.connect(ftpHost, ftpPort);              // 连接FTP服务器
            logger.info("开通一个端口来传输数据");
            ftpClient.enterLocalPassiveMode();  //被动模式

            ftpClient.login(ftpUserName, ftpPassword);        // 登陆FTP服务器
            ftpClient.setFileTransferMode(FTP.BINARY_FILE_TYPE);//设置传输模式,这里是二进制图像
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);//设置要传输的文件类型,这里是二进制图像
            ftpClient.setBufferSize(65536);


            logger.info("ftpClient.getReplyCode:" + ftpClient.getReplyCode());
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                logger.info("未连接到FTP，用户名或密码错误。");
                ftpClient.disconnect();
                throw new IOException("login fail!");
            } else {
                logger.info("FTP连接成功。");
            }
        } catch (SocketException e) {
            e.printStackTrace();
            logger.info("FTP的IP地址可能错误，请正确配置。");
        } catch (IOException e) {
            e.printStackTrace();
            logger.info("FTP的端口错误,请正确配置。");
        }

        return ftpClient;
    }

    /**
     * 获取FTPClient对象
     *
     * @return
     */
    public static FTPClient getFTPClients() {
        FTPClient ftpClient = new FTPClient();
        try {

            // 设置连接超时时间
            ftpClient.setConnectTimeout(50 * 1000);
            // 设置数据超时时间
            ftpClient.setDataTimeout(50 * 1000);
            ftpClient.connect(ftpHost, ftpPort);              // 连接FTP服务器
            ftpClient.login(ftpUserName, ftpPassword);        // 登陆FTP服务器
            ftpClient.enterLocalPassiveMode();//被动模式
            // ftpClient.enterLocalActiveMode();//主动模式

            ftpClient.setFileTransferMode(FTP.BINARY_FILE_TYPE);//设置传输模式,这里是二进制图像
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);//设置要传输的文件类型,这里是二进制图像
            // ftpClient.setActivePortRange(1025,1028);


            logger.info("ftpClient.getReplyCode:" + ftpClient.getReplyCode());
            if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                logger.info("未连接到FTP，用户名或密码错误。");
                ftpClient.disconnect();
                throw new IOException("login fail!");
            } else {
                logger.info("FTP连接成功。");
            }
        } catch (SocketException e) {
            e.printStackTrace();
            logger.info("FTP的IP地址可能错误，请正确配置。");
        } catch (IOException e) {
            e.printStackTrace();
            logger.info("FTP的端口错误,请正确配置。");
        }

        return ftpClient;
    }

    /*
     * 从FTP服务器下载文件
     * @param ftpPath             FTP服务器中文件所在路径 格式： ftptest/aa
     * @param localPath           下载到本地的位置 格式：H:/download
     * @param fileName            FTP服务器上要下载的文件名称
     * @param targetFileName      FTP服务器上要下载的文件名称
     */
    public static void downloadFtpFile(String ftpPath, String localPath, String fileName, String targetFileName) {

        FTPClient ftpClient = null;
        try {
            ftpClient = getFTPClient();
            ftpClient.changeWorkingDirectory(ftpPath);

            String f_ame = new String(fileName.getBytes("GBK"), FTP.DEFAULT_CONTROL_ENCODING);  //编码文件格式,解决中文文件名

            File localFile = new File(localPath + File.separatorChar + targetFileName);
            OutputStream os = new FileOutputStream(localFile);
            ftpClient.retrieveFile(f_ame, os);
            os.close();
            ftpClient.logout();

        } catch (FileNotFoundException e) {
            logger.error("没有找到" + ftpPath + "文件");
            e.printStackTrace();
        } catch (SocketException e) {
            logger.error("连接FTP失败.");
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("文件读取错误。");
            e.printStackTrace();
        }
    }


    /**
     * Description:             向FTP服务器上传文件
     *
     * @param ftpPath  FTP服务器文件存放路径
     * @param filename 上传到FTP服务器上的文件名
     * @param input    输入流
     * @return 成功返回true，否则返回false
     */
    public static String uploadFile(String ftpPath, String filename, InputStream input) {
        String result = "";
        FTPClient ftpClient = new FTPClient();


        try {
            int reply;
            ftpClient = getFTPClients();
            logger.info("进入目录前的路径:" + ftpClient.printWorkingDirectory());
            //创建并进入不存在的目录
            if (!ftpClient.changeWorkingDirectory(ftpPath)) {
                ftpClient.mkd(ftpPath);
                ftpClient.changeWorkingDirectory(ftpPath);
            }

            logger.info("当前目录为：" + ftpClient.printWorkingDirectory());

            logger.info("ftp上传路径:" + ftpPath);
            reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftpClient.disconnect();
                logger.error("附件上传失败!错误码:" + reply);
                throw new IOException("login fail!");
            }

            filename = new String(filename.getBytes("GBK"), FTP.DEFAULT_CONTROL_ENCODING);    //编码文件名，支持中文文件名
            logger.info("开始上传!" + filename);

            //上传文件
            boolean blftp = ftpClient.storeFile(ftpPath + "/" + filename, input);
            if (!blftp) {
                logger.error("附件上传失败!");
                throw new IOException("login fail!");
            }
            logger.info("上传中...");
            input.close();
            ftpClient.logout();
            result = ftpPath + "/" + filename;

        } catch (IOException e) {
            logger.error("上传文件出错,请检查接口FtpUtil.uploadFile()", e);
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                    logger.error("上传文件出错,请检查接口FtpUtil.uploadFile()", ioe);
                }
            }
        }
        return result;
    }

    /**
     * 获取ftp上文件的InputStream
     *
     * @param ftpDirName  ftp文件夹名称
     * @param ftpFileName ftp文件名称
     * @return
     * @throws IOException
     */
    public static byte[] getInputStream(String ftpDirName, String ftpFileName) {
        //FTP客户端
        FTPClient ftp = getFTPClient();
        //流对象
        InputStream inputStream = null;
        byte[] bytes = null;
        try {
            logger.info("ftp切换前服务器路径为:" + ftp.printWorkingDirectory());
            logger.info("传入的路径为:" + ftpDirName);

            String dir = new String(ftpDirName.getBytes("GBK"), "iso-8859-1");
            boolean b = ftp.changeWorkingDirectory(dir);
            if (b) {
                logger.info("进入目录成功！:" + b);
            } else {
                logger.error("切换目录失败：" + ftpDirName);
                return null;
            }
            logger.info("ftp切换后服务器路径为:" + ftp.printWorkingDirectory());
            // 一定要加上字符集指定，因为获取文件时有中文，会出现乱码而获取不到。


            String fileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
//            String fileName = ftpFileName;

            // 每次数据连接之前，ftp client告诉ftp server开通一个端口来传输数据，ftp server可能每次开启不同的端口来传输数据，
            logger.info("开通一个端口来传输数据");
            logger.info("getReplyCode:" + ftp.getReplyCode());
            logger.info("fileName:" + fileName);

            // 但是在Linux上，由于安全限制，可能某些端口没有开启，所以就出现阻塞。
            inputStream = ftp.retrieveFileStream(fileName);
            logger.info("获取文件流数据！");
            if (null == inputStream) {
                logger.error(fileName + "在ftp上读取失败!");
                return null;
            }
            bytes = IOUtils.toByteArray(inputStream);

            logger.info("获取文件字节大小：" + bytes.length);
            ftp.getReply();
            ftp.logout();
            return bytes;
        } catch (IOException e) {
            logger.error("FTPUtil.getInputStream()方法异常!", e);
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (ftp != null) {
                    ftp.completePendingCommand();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytes;
    }

    /**
     * 判断附件在ftp上是否存在
     *
     * @return boolean
     * @author <a href="mailto:wanglu@smartdot.com.cn">wanglu</a>
     * @Date 2021/7/13
     */
    public static boolean fileExist(String ftpHost, String ftpUserName, String ftpPassword, int ftpPort, String
            ftpPath, String filename) {
        boolean result = false;
        FTPClient ftpClient = new FTPClient();
        try {
            ftpClient = getFTPClient();
            ftpClient.changeWorkingDirectory(ftpPath);
            FTPFile[] ftpFiles = ftpClient.listFiles(filename);
            if (ftpFiles.length == 0) {
                return result;
            }
            ftpClient.logout();
            result = true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return result;
    }

    public static void main(String[] args) throws IOException {


        //获取ftp上文件的InputStream
//        byte[] inputStream = FtpUtil.getInputStream("/home/hd/temp/", "111.txt");

        String ftpPath = "/home/hd/temp/";
        String fileName = "222.pdf";

        //上传一个文件
        FileInputStream in = new FileInputStream(new File("C:\\Users\\26372\\Desktop\\temp\\test\\222.pdf"));
        FtpUtil.uploadFile(ftpPath, fileName, in);


        FtpUtil.downloadFtpFile(ftpPath, "C:\\Users\\26372\\Desktop\\temp\\", "222.pdf", "测试下载文件.pdf");

    }

}